package com.lagou.edu.factory;

import com.lagou.edu.anno.Autowired;
import com.lagou.edu.anno.Repository;
import com.lagou.edu.anno.Service;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.MethodParameterScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ConfigurationBuilder;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author yuhe
 * <p>
 * 工厂类，生产对象（使用反射技术）
 */
public class AnnotationBeanFactory {

    /**
     * 写死一个扫描包路径，或者配置在配置文件中进行读取，为方便实现效果，省去配置文件的读取。
     */
    private static String packagePath = "com.lagou.edu";

    /**
     * 任务一：扫描注解，通过反射技术实例化对象并且存储待用（map集合）
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     */

    private static Map<String, Object> map = new HashMap<>();  // 存储对象

    private static Set<Class<?>> beanClasses = new HashSet<>();


    static {
        System.err.println("================================");
        // 任务一：读取包下注解l，通过反射技术实例化对象并且存储待用（map集合）
        Reflections reflections = new Reflections(new ConfigurationBuilder()
                .forPackages(packagePath) // 指定路径URL
                .addScanners(new SubTypesScanner()) // 添加子类扫描工具
                .addScanners(new FieldAnnotationsScanner()) // 添加 属性注解扫描工具
                .addScanners(new MethodAnnotationsScanner()) // 添加 方法注解扫描工具
                .addScanners(new MethodParameterScanner()) // 添加方法参数扫描工具
        );
        try {
            //注解实现解析Bean,简单实现，我们可以把Repository和Service看成一个类型处理
            getBeanFromClazz(reflections, Repository.class);
            getBeanFromClazz(reflections, Service.class);

            Set<Field> fields = reflections.getFieldsAnnotatedWith(Autowired.class);
            if (fields != null) {
                for (Field field : fields) {
                    field.setAccessible(true);
                    Class<?> declaringClass = field.getDeclaringClass();

                    //获取所在类
                    Object clazzObject = map.get(getDefName(declaringClass));
                    Annotation[] anns = field.getAnnotations();
                    for (Annotation ann : anns) {
                        if (ann instanceof Autowired) {
                            Class<?> type = field.getType();
                            AnnotatedType annotatedType = field.getAnnotatedType();

                            // 获取fild的类型，并使用该类型的newInstance()方法生成一个对象
                            Class genericType = (Class) field.getGenericType();
                            String name = getDefName(genericType);
                            Object o = map.get(name);
//                            // 使用Filed的set方法为对象set值
                            field.setAccessible(true);
                            field.set(clazzObject, o);

                            // 遍历父对象中的所有方法，找到"set" + name
//                            Method[] methods = declaringClass.getMethods();
//                            for (int j = 0; j < methods.length; j++) {
//                                Method method = methods[j];
//                                if(method.getName().equalsIgnoreCase("set" + name)) {  // 该方法就是 setAccountDao(AccountDao accountDao)
//                                    method.invoke(clazzObject,o);
//                                }
//                            }

                            //更新缓存中的对象
                            map.put(getDefName(declaringClass), clazzObject);
                        }
                    }
                }
            }

        } catch (IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }

    }


    // 任务二：对外提供获取实例对象的接口（根据id获取）
    public static Object getBean(String id) {
        return map.get(id);
    }


    /**
     * 首字母变小写
     *
     * @param s
     * @return
     */
    private static String toLowerCaseFirst(String s) {
        if (s == null) {
            return null;
        }
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
        }
    }

    /**
     * 获取初始化时所有包含相关注解的bean
     *
     * @param classInfo
     * @return
     */
    private static String getDefNameInit(Class<?> classInfo) {
        String className = "";
        boolean annotationPresent2 = classInfo.isAnnotationPresent(Repository.class);
        if (annotationPresent2) {
            Repository name2 = classInfo.getAnnotation(Repository.class);
            String nameValue2 = name2.value();
            if (!nameValue2.equalsIgnoreCase("")) {
                return nameValue2;
            }
        }
        boolean annotationPresent = classInfo.isAnnotationPresent(Service.class);
        if (annotationPresent) {
            Service name = classInfo.getAnnotation(Service.class);
            String nameValue = name.value();
            if (!nameValue.equalsIgnoreCase("")) {
                return nameValue;
            }
        }
        Class<?>[] interfaces = classInfo.getInterfaces();
        if (interfaces != null && interfaces.length > 0) {
            for (Class<?> anInterface : interfaces) {
                String simpleName = anInterface.getSimpleName();
                if (classInfo.getSimpleName().contains(simpleName)) {
                    className = simpleName;
                }
            }
        } else {
            className = classInfo.getSimpleName();
        }
        return toLowerCaseFirst(className);
    }


    /**
     * 根据autowire的filed获取获取bean的别名
     *
     * @param classInfo
     * @return
     */
    private static String getDefName(Class<?> classInfo) {
        String className = "";
        Class<?> clazz = classInfo;
        boolean anInterface1 = classInfo.isInterface();
        if (anInterface1) {
            for (Class<?> aClass : beanClasses) {
                if (classInfo.isAssignableFrom(aClass) && !classInfo.equals(aClass)) {
                    //TODO 本项目一个接口只有一个实现类，如果有多个，此处需要有额外的逻辑进行处理
                    clazz = aClass;
                }
            }
        }
        className = clazz.getSimpleName();
        boolean annotationPresent2 = clazz.isAnnotationPresent(Repository.class);
        if (annotationPresent2) {
            Repository name2 = clazz.getAnnotation(Repository.class);
            String nameValue2 = name2.value();
            if (!nameValue2.equalsIgnoreCase("")) {
                className = nameValue2;
            }
        }
        boolean annotationPresent = clazz.isAnnotationPresent(Service.class);
        if (annotationPresent) {
            Service name = clazz.getAnnotation(Service.class);
            String nameValue = name.value();
            if (!nameValue.equalsIgnoreCase("")) {
                className = nameValue;
            }
        }
        return toLowerCaseFirst(className);
    }


    /**
     * 解析指定的注解并加入到Object map和Class set中
     *
     * @param reflections
     * @param annotation
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private static void getBeanFromClazz(Reflections reflections, final Class<? extends Annotation> annotation) throws IllegalAccessException, InstantiationException {
        Set<Class<?>> classes = reflections.getTypesAnnotatedWith(annotation);
        beanClasses.addAll(classes);
        for (Class<?> classInfo : classes) {
            //判断类上是否有自定义ExtService注解
            Annotation annotation1 = classInfo.getAnnotation(annotation);
            if (annotation1 != null) {
                String id = getDefNameInit(classInfo);
                //如果当前类上有注解，将该类的信息，添加到map集合
                map.put(id, classInfo.newInstance());
            }
        }
    }

}
